package com.riche.contractbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.riche.contractbackend.common.ErrorCode;
import com.riche.contractbackend.exception.BusinessException;
import com.riche.contractbackend.mapper.TeamMapper;
import com.riche.contractbackend.model.domain.Team;
import com.riche.contractbackend.model.domain.User;
import com.riche.contractbackend.model.domain.UserTeam;
import com.riche.contractbackend.model.dto.TeamQuery;
import com.riche.contractbackend.model.enums.TeamStatusEnum;
import com.riche.contractbackend.model.request.TeamJoinRequest;
import com.riche.contractbackend.model.request.TeamQuiteRequest;
import com.riche.contractbackend.model.request.TeamUpdateRequest;
import com.riche.contractbackend.model.vo.TeamUserListVo;
import com.riche.contractbackend.model.vo.TeamUserVO;
import com.riche.contractbackend.model.vo.UserVO;
import com.riche.contractbackend.service.TeamService;
import com.riche.contractbackend.service.UserService;
import com.riche.contractbackend.service.UserTeamService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: TeamServiceImpl
 * @Description: 队伍接口层实现类
 * @Author: Gaoruiqi
 * @Date: 2025-09-10 19:51
 * @Version: 1.0
 **/

@Service
@Slf4j
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team> implements TeamService {

    @Resource
    private UserTeamService userTeamService;

    @Resource
    private UserService userService;
    @Resource
    private RedissonClient redissonClient;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public long addTeam(Team team, User loginUser) {
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        final Long loginUserId = loginUser.getId();
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("userId", loginUserId);
        long count = userTeamService.count(userTeamQueryWrapper);
        if (count > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多创建加入 5 个队伍");
        }
        int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);
        log.info("maxNum: {}", maxNum);
/*
        todo 等效代码
        int maxNum;
        if (team.getMaxNum() != null) {
            maxNum = team.getMaxNum();
        } else {
            maxNum = 0;
        }
        */
        if (maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不满足要求");
        }
        if (StringUtils.isBlank(team.getName()) || team.getName().length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍名称不满足要求");
        }
        if (StringUtils.isNotBlank(team.getDescription()) && team.getDescription().length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述过长");
        }
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(team.getStatus());
        if (statusEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");
        }
        if (TeamStatusEnum.SECRET.equals(statusEnum)) {
            if (StringUtils.isBlank(team.getPassword()) || team.getPassword().length() > 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码不满足要求");
            }
        }
        if (new Date().after(team.getExpireTime())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间 > 当前时间");
        }

        // todo 有 bug
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        // 判断当前用户是否已创建过队伍
        queryWrapper.eq("userId", loginUser);
        long hashTeamNum = count(queryWrapper);
        if (hashTeamNum >= 5) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户最多创建 5 个队伍");
        }

        // 插入队伍信息到队伍表
        team.setId(null);
        team.setUserId(loginUserId);
        boolean result = this.save(team);
        Long teamId = team.getId();
        if (!result || teamId == null) {
            // 抛出异常，事务自动回滚
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建队伍失败");
        }
        // 插入用户 - 队伍关系到队伍表
        UserTeam userTeam = new UserTeam();
        userTeam.setId(null);
        userTeam.setUserId(loginUserId);
        userTeam.setJoinTime(LocalDateTime.now());
        userTeam.setTeamId(teamId);

        result = userTeamService.save(userTeam);
        if (!result) {
            // 抛出异常，事务自动回滚
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建队伍失败");
        }
        return teamId;
    }

    @Override
    public TeamUserListVo listTeams(TeamQuery teamQuery, User loginUser) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("userId", loginUser.getId());
        boolean currentUserIsCreateTeam = this.count(teamQueryWrapper) == 0;
        // 1. 组合查询条件
        if (teamQuery != null) {
            Long teamId = teamQuery.getId();
            if (teamId != null && teamId > 0) {
                queryWrapper.eq("id", teamId);
            }
            String searchText = teamQuery.getSearchText();
            if (StringUtils.isNotBlank(searchText)) {
                queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
            }
            Integer teamMaxNum = teamQuery.getMaxNum();
            if (teamMaxNum != null && teamMaxNum > 0) {
                queryWrapper.eq("maxNum", teamMaxNum);
            }
            Long userId = teamQuery.getUserId();
            if (userId != null && userId > 0) {
                queryWrapper.eq("userId", userId);
            }
            Integer teamStatus = teamQuery.getStatus();
            TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(teamStatus);
            // 如果不存在枚举值，则返回默认值
            if (statusEnum == null) {
                statusEnum = TeamStatusEnum.PUBLIC;
            }
            boolean isAmin = userService.isAdmin(loginUser);
            if (!isAmin && !statusEnum.equals(TeamStatusEnum.PUBLIC)) {
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
            queryWrapper.eq("status", statusEnum.getValue());
        }
        // 不展示已过期队伍
        queryWrapper.and(qw -> qw.gt("expireTime", LocalDateTime.now())).or().isNull("expireTime");
        queryWrapper.orderByDesc("createTime");
        List<Team> teamList = this.list(queryWrapper);
        // 2. 关联查询用户信息
        if (CollectionUtils.isEmpty(teamList)) {
            return new TeamUserListVo();
        }
        // 查询队伍和创建人的信息 （主查询是队伍）
        // select * from team t left join user u on t.userId = u.id
        // 查询队伍和已加入队伍成员的信息
        // select * from team t join user_team ut on t.id = ut.teamId left join user u on ut.userId = u.id
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        TeamUserListVo teamUserListVo = new TeamUserListVo();
        for (Team team : teamList) {
            Long userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            User user = userService.getById(userId);
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);
            if (user != null) {
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user, userVO);
                teamUserVO.setCreateUser(userVO);
            }
            teamUserVOList.add(teamUserVO);
        }
        teamUserListVo.setCurrentUserIsCreateTeam(currentUserIsCreateTeam);
        teamUserListVo.setTeamUserVOList(teamUserVOList);
        return teamUserListVo;
    }

    @Override
    public boolean updateById(TeamUpdateRequest teamUpdateRequest, User loginUser) {
        if (teamUpdateRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = teamUpdateRequest.getId();
        if (id == null || id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team oldTeam = this.getById(id);
        if (oldTeam == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
        }
        // 只有管理员或者队伍的创建者可以修改
        if (!oldTeam.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH, "无权限");
        }
        TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(teamUpdateRequest.getStatus());
        if (enumByValue.equals(TeamStatusEnum.SECRET)) {
            if (StringUtils.isBlank(teamUpdateRequest.getPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "加密房间必须设置密码");
            }
        }
        if (enumByValue.equals(TeamStatusEnum.PUBLIC)) {
            if (teamUpdateRequest.getPassword() != null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "公开房间不能设置密码");
            }
        }
        Team updateTeam = new Team();
        BeanUtils.copyProperties(teamUpdateRequest, updateTeam);
        boolean update = this.updateById(updateTeam);
        return update;
    }

    @Override
    public Boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {
        if (teamJoinRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = teamJoinRequest.getTeamId();
        if (teamId == null || teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "加入的队伍不存在");
        }
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "加入的队伍不存在");
        }
        if (team.getExpireTime() != null && team.getExpireTime().before(new Date())) {
            throw new BusinessException(ErrorCode.JOIN_TEAM_ERROR, "队伍已过期");
        }
        Integer status = team.getStatus();
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getEnumByValue(status);
        if (TeamStatusEnum.PRIVATE.equals(teamStatusEnum)) {
            throw new BusinessException(ErrorCode.JOIN_TEAM_ERROR, "禁止加入私有队伍");
        }
        String password = teamJoinRequest.getPassword();
        if (TeamStatusEnum.SECRET.equals(teamStatusEnum)) {
            if (StringUtils.isBlank(password) || !password.equals(team.getPassword())) {
                throw new BusinessException(ErrorCode.JOIN_TEAM_ERROR, "密码错误");
            }
        }
        Long userId = loginUser.getId();
        // 分布式锁：
        RLock lock = redissonClient.getLock("contract:join_team");
        try {
            while (true) {
                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
                    log.info("getLock：{}", Thread.currentThread().getId());
                    // 查询数据库，判断条件
                    QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId", userId);
                    long count = userTeamService.count(queryWrapper);
                    if (count >= 5) {
                        throw new BusinessException(ErrorCode.JOIN_TEAM_ERROR, "最多创建加入五个队伍");
                    }
                    // 禁止加入人数满的队伍
                    queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("teamId", teamId);
                    long countTeam = userTeamService.count(queryWrapper);
                    if (countTeam >= team.getMaxNum()) {
                        throw new BusinessException(ErrorCode.JOIN_TEAM_ERROR, "队伍已满");
                    }
                    // 禁止加入已经加入的队伍
                    queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId", userId).eq("teamId", teamId);
                    long hasJoin = userTeamService.count(queryWrapper);
                    if (hasJoin > 0) {
                        throw new BusinessException(ErrorCode.JOIN_TEAM_ERROR, "已加入过该队伍");
                    }
                    // 修改队伍信息
                    UserTeam userTeam = new UserTeam();
                    userTeam.setUserId(userId);
                    userTeam.setTeamId(teamId);
                    userTeam.setJoinTime(LocalDateTime.now());
                    return userTeamService.save(userTeam);
                }
            }
        } catch (Exception e) {
            log.error("redissonClient.getLock(join_team) error", e);
            return false;
        } finally {
            if (lock.isHeldByCurrentThread()) {
                log.info("释放锁成功");
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean quitTeam(TeamQuiteRequest teamQuiteRequest, User loginUser) {
        if (teamQuiteRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数有误");
        }
        Long teamId = teamQuiteRequest.getTeamId();
        if (teamId == null || teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数有误");
        }
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
        }
        Long userId = loginUser.getId();
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId", teamId).eq("userId", userId);
        long count = userTeamService.count(queryWrapper);
        if (count <= 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "未加入队伍");
        }
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId", teamId);
        long countTeam = userTeamService.count(queryWrapper);
        log.info("统计队伍中有几个人: {}", countTeam);
        boolean removeResult;
        if (countTeam == 1) {
            // 删除队伍和所有加入队伍的关系
            this.removeById(teamId);
        } else {
            // 是否为队长
            if (Objects.equals(team.getUserId(), userId)) {
                // 把队伍转移给最早加入的队伍
                // 1. 查询已加入队伍的的所有用户的加入时间
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId", teamId);
                // 拼接语句，
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if (CollectionUtils.isEmpty(userTeamList) || userTeamList.size() <= 1) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);
                Long nextTeamLeaderId = nextUserTeam.getUserId();
                // 更新队伍的队长
                Team updateTeam = new Team();
                updateTeam.setId(teamId);
                updateTeam.setUserId(nextTeamLeaderId);
                boolean result = this.updateById(updateTeam);
                if (!result) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新队伍队长失败");
                }
            }
        }
        // 移除当前用户在队伍用户表中的关系
        queryWrapper.eq("teamId", teamId).eq("userId", userId);
        removeResult = userTeamService.remove(queryWrapper);
        if (!removeResult) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "移除失败");
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTeam(long teamId, User loginUser) {
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
        }
        if (!Objects.equals(team.getUserId(), loginUser.getId())) {
            throw new BusinessException(ErrorCode.FORBIDDEN_ERROR, "无操作权限");
        }
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId", teamId);
        boolean remove = userTeamService.remove(queryWrapper);
        if (!remove) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "解散失败失败");
        }
        return this.removeById(teamId);
    }
}
